package pe.com.casadesign.dao.impl;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;

import javax.sql.DataSource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.jdbc.core.simple.SimpleJdbcCall;
import org.springframework.stereotype.Repository;

import pe.com.casadesign.dao.MantenimientoDAO;
import pe.com.casadesign.domain.Item;
import pe.com.casadesign.domain.ListaItem;
import pe.com.casadesign.domain.ListaMantenimiento;
import pe.com.casadesign.domain.Mantenimiento;
import pe.com.casadesign.domain.Moneda;
import pe.com.casadesign.domain.Producto;
import pe.com.casadesign.domain.Proveedor;
import pe.com.casadesign.domain.Tienda;
import pe.com.casadesign.domain.Usuario;

/**
 * Implementacion de MantenimentoDAO.
 * 
 * @author Pedro Vera
 * 
 */
@Repository
public class MantenimentoDAOImpl implements MantenimientoDAO {
	private static final Logger logger = LoggerFactory.getLogger(MantenimentoDAOImpl.class);
	
	// Nombre Procedimientos Almacenados
	private static String SP_LISTAR_MANTENIMIENTO = "SP_LISTAR_MANTENIMIENTO";
	private static String SP_OBTENER_MANTENIMIENTO = "SP_OBTENER_MANTENIMIENTO";
	private static String SP_REGISTRAR_MANTENIMIENTO = "SP_REGISTRAR_MANTENIMIENTO";
	private static String SP_REGISTRAR_DET_MANTENIMIENTO = "SP_REGISTRAR_DET_MANTENIMIENTO";
	private static String SP_ACTUALIZAR_ESTADO_ITEM = "SP_ACTUALIZAR_ESTADO_ITEM";
	private static String SP_MODIFICAR_MANTENIMIENTO = "SP_MODIFICAR_MANTENIMIENTO";
		
	// Parametros de Entrada
	private static String PARAM_CODMANTENIMIENTO = "p_codmantenimiento";
	private static String PARAM_CODPROVEEDOR = "p_codproveedor";
	private static String PARAM_CODUSUARIO = "p_codusuario";
	private static String PARAM_ESTADO = "p_estado";
	
	private static String PARAM_ITEM_CODITEM = "p_coditem";
	private static String PARAM_ITEM_ESTADO = "p_estado";
	
	// Parametros de Salida
	private static String CODMANTENIMIENTO = "CODMANTENIMIENTO";
	private static String CODPROVEEDOR = "CODPROVEEDOR";
	private static String CODUSUARIO = "CODUSUARIO";
	private static String ESTADO = "ESTADO";
	private static String FECHAREGISTRO = "FECHAREGISTRO";
	
	private static String PROVEEDOR_IDENTIFICACION = "IDENTIFICACION";
	private static String PROVEEDOR_RAZONSOCIAL = "RAZONSOCIAL";
	
	private static String USUARIO_NOMBRESYAPELLIDOS = "NOMBRESYAPELLIDOS";
	
	private static String ITEM_CODITEM = "CODITEM";
	private static String ITEM_CODIFICACION = "CODIFICACION";
	private static String ITEM_ESTADO = "ESTADO";
	private static String ITEM_PRECIOCOMPRA = "PRECIOCOMPRA";
	private static String ITEM_CODMONEDA = "CODMONEDA";
	private static String ITEM_CODTIENDA = "CODTIENDA";
	
	private static String PRODUCTO_CODPRODUCTO = "CODPRODUCTO";
	private static String PRODUCTO_DESCRIPCION = "DESCRIPCION";
	
	private static String LISTADO = "LISTADO";
	private static String LISTADO_LINEAS = "LISTADO_LINEAS";
	
	private static String TOTAL_FILAS_AFECTADAS = "#update-count-1";
	
	private JdbcTemplate jdbcTemplate;

	@Autowired
    public void setDataSource(DataSource dataSource)
    {
        this.jdbcTemplate = new JdbcTemplate(dataSource);
    }
	
	@Override
	public ListaMantenimiento listarMantenimiento(Mantenimiento mantenimiento) {
		logger.info("listarMantenimiento");

		// Instanciando variable para llamado de SP
	    SimpleJdbcCall llamarSP = new SimpleJdbcCall(jdbcTemplate).withProcedureName(SP_LISTAR_MANTENIMIENTO).
	    						  returningResultSet(LISTADO, new RowMapper<Mantenimiento>(){
									@Override
									public Mantenimiento mapRow(final ResultSet rs, final int numRow) throws SQLException
								    {
								        final Mantenimiento mantenimiento = new Mantenimiento();
								        mantenimiento.setCodMantenimiento(rs.getInt(CODMANTENIMIENTO));
								        
								        Proveedor proveedor =  new Proveedor();
								        proveedor.setCodProveedor(rs.getInt(CODPROVEEDOR));
								        proveedor.setIdentificacion(rs.getString(PROVEEDOR_IDENTIFICACION));
								        proveedor.setRazonSocial(rs.getString(PROVEEDOR_RAZONSOCIAL));
								        mantenimiento.setProveedor(proveedor);
								        
								        Usuario usuario = new Usuario();
								        usuario.setCodUsuario(rs.getInt(CODUSUARIO));
								        usuario.setNombresyApellidos(rs.getString(USUARIO_NOMBRESYAPELLIDOS));
								        mantenimiento.setUsuario(usuario);
								        
								        mantenimiento.setEstado(rs.getString(ESTADO));
								        mantenimiento.setFechaRegistro(rs.getDate(FECHAREGISTRO).toString());
								        return mantenimiento;
								    }
	    						  }
								);

	    // Estableciendo parametros de entrada al SP
	    SqlParameterSource parametros = new MapSqlParameterSource()
	    								.addValue(PARAM_CODMANTENIMIENTO, mantenimiento.getCodMantenimiento())
	    								.addValue(PARAM_CODPROVEEDOR, mantenimiento.getProveedor().getCodProveedor())
	    								.addValue(PARAM_ESTADO, mantenimiento.getEstado()); 

	    // Establecer parametros y ejecutar SP
        Map<String,Object> data = llamarSP.execute(parametros);

        // Obteniendo lista generada de ejecutar SP
		@SuppressWarnings("unchecked")
		List<Mantenimiento> listaMantenimiento = (List<Mantenimiento>)data.get(LISTADO);
        
		// Instanciando objeto ListaMantenimiento
		ListaMantenimiento listaMantenimientoResultado = new ListaMantenimiento();
        // Estableciendo resultado al objeto listaMantenimientoResultado
		listaMantenimientoResultado.setLista(listaMantenimiento);
        
        if (logger.isDebugEnabled() && listaMantenimientoResultado != null)
        {
            logger.debug("size=" + listaMantenimientoResultado.size());
        }
        return listaMantenimientoResultado;
	}

	@Override
	public Mantenimiento obtenerMantenimiento(Mantenimiento mantenimiento) {
		logger.info("obtenerMantenimiento");

		// Instanciando variable para llamado de SP
	    SimpleJdbcCall llamarSP = new SimpleJdbcCall(jdbcTemplate).withProcedureName(SP_OBTENER_MANTENIMIENTO).
	    						  returningResultSet(LISTADO, new RowMapper<Mantenimiento>(){
									@Override
									public Mantenimiento mapRow(final ResultSet rs, final int numRow) throws SQLException
								    {
								        final Mantenimiento mantenimiento = new Mantenimiento();
								        mantenimiento.setCodMantenimiento(rs.getInt(CODMANTENIMIENTO));
								        
								        Proveedor proveedor =  new Proveedor();
								        proveedor.setCodProveedor(rs.getInt(CODPROVEEDOR));
								        proveedor.setIdentificacion(rs.getString(PROVEEDOR_IDENTIFICACION));
								        proveedor.setRazonSocial(rs.getString(PROVEEDOR_RAZONSOCIAL));
								        mantenimiento.setProveedor(proveedor);
								        
								        Usuario usuario = new Usuario();
								        usuario.setCodUsuario(rs.getInt(CODUSUARIO));
								        usuario.setNombresyApellidos(rs.getString(USUARIO_NOMBRESYAPELLIDOS));
								        mantenimiento.setUsuario(usuario);
								        
								        mantenimiento.setEstado(rs.getString(ESTADO));
								        mantenimiento.setFechaRegistro(rs.getDate(FECHAREGISTRO).toString());
								        return mantenimiento;
								    }
	    						  }
								)
								.returningResultSet(LISTADO_LINEAS, new RowMapper<Item>(){
									@Override
									public Item mapRow(final ResultSet rs, final int numRow) throws SQLException
								    {
								        final Item item = new Item();
								        item.setCodItem(rs.getInt(ITEM_CODITEM));
								        item.setCodificacion(rs.getString(ITEM_CODIFICACION));
								        item.setEstado(rs.getString(ITEM_ESTADO));
								        item.setPrecioCompra(rs.getDouble(ITEM_PRECIOCOMPRA));
								        
								        Moneda moneda = new Moneda();
								        moneda.setCodigo(rs.getInt(ITEM_CODMONEDA));
								        item.setMoneda(moneda);
								        
								        Tienda tienda = new Tienda();
								        tienda.setCodigo(rs.getInt(ITEM_CODTIENDA));
								        item.setTienda(tienda);
								        
								        Producto producto = new Producto();
								        producto.setCodigo(rs.getInt(PRODUCTO_CODPRODUCTO));
								        producto.setDescripcion(rs.getString(PRODUCTO_DESCRIPCION));
								        item.setProducto(producto);
								        
								        return item;
								    }
	    						  });

	    // Estableciendo parametros de entrada al SP
	    SqlParameterSource parametros = new MapSqlParameterSource()
	    								.addValue(PARAM_CODMANTENIMIENTO, mantenimiento.getCodMantenimiento()); 

	    // Establecer parametros y ejecutar SP
        Map<String,Object> data = llamarSP.execute(parametros);

        // Obteniendo lista generada de ejecutar SP
		@SuppressWarnings("unchecked")
		List<Mantenimiento> listaMantenimiento = (List<Mantenimiento>)data.get(LISTADO);
        
		// Declarando objeto mantenimiento Obtenido
 		Mantenimiento mantenimientoObtenido = null;
 		
 		if (logger.isDebugEnabled() && listaMantenimiento != null)
        {
            logger.debug("size=" + listaMantenimiento.size());
        }
 		
 		if (listaMantenimiento != null && listaMantenimiento.size()>0){
 			// Obteniendo el primer elemento de la lista de mantenimiento
 			mantenimientoObtenido = listaMantenimiento.get(0);
 		
	        // Obteniendo lista de lineas generada de ejecutar SP
			@SuppressWarnings("unchecked")
			List<Item> listaItem= (List<Item>)data.get(LISTADO_LINEAS);
	        
			// Instanciando objeto ListaItem
			ListaItem listaItemResultado = new ListaItem();
	        // Estableciendo resultado al objeto listaItemResultado
			listaItemResultado.setLista(listaItem);
	        
			// Asignando lista de lineas al objeto mantenimiento creado
			mantenimientoObtenido.setListaItem(listaItemResultado);
			
	        if (logger.isDebugEnabled() && listaItemResultado != null)
	        {
	            logger.debug("sizeLineas=" + listaItemResultado.size());
	        }
 		}
 		
 		return mantenimientoObtenido;
	}

	@Override
	public boolean registrarMantenimiento(Mantenimiento mantenimiento) {
		logger.info("registrarMantenimiento");
		
		int resultado = 0;
		
		// Instanciando variable para llamado de SP
	    SimpleJdbcCall llamarSP = new SimpleJdbcCall(jdbcTemplate).withProcedureName(SP_REGISTRAR_MANTENIMIENTO);

	    // Estableciendo parametros de entrada al SP
	    SqlParameterSource parametros = new MapSqlParameterSource()
	    								.addValue(PARAM_CODPROVEEDOR, mantenimiento.getProveedor().getCodProveedor())
	    								.addValue(PARAM_CODUSUARIO, mantenimiento.getUsuario().getCodUsuario())
	    								.addValue(PARAM_ESTADO, mantenimiento.getEstado());
	    
	    // Establecer parametros y ejecutar SP
	    Map<String,Object> data = llamarSP.execute(parametros);
	    
	    // Obteniendo el total de filas afectadas al ejecutar SP
	    resultado += (Integer) data.get(TOTAL_FILAS_AFECTADAS);
	    
	    logger.debug("codigo generado:" + data.get(PARAM_CODMANTENIMIENTO));

	    // Obteniendo codigo de mantenimiento
	    int codigoMantenimiento = (Integer)data.get(PARAM_CODMANTENIMIENTO);

	    // Estableciendo codigo generado
	    mantenimiento.setCodMantenimiento(codigoMantenimiento);
	    
	    // Obteniendo lista de item
	    ListaItem listaItem = mantenimiento.getListaItem();
	    
	    // Si existen items entonces asociarlos
	    if(listaItem != null && listaItem.getLista() != null){
		    // Instanciando variable para llamado de SP
		    SimpleJdbcCall llamarSPLineas = new SimpleJdbcCall(jdbcTemplate).withProcedureName(SP_REGISTRAR_DET_MANTENIMIENTO);
	
		    for (Item item : listaItem.getLista()){
			    // Estableciendo parametros de entrada al SP
			    SqlParameterSource parametrosDetalle = new MapSqlParameterSource()
						    								.addValue(PARAM_CODMANTENIMIENTO, codigoMantenimiento)
						    								.addValue(PARAM_ITEM_CODITEM, item.getCodItem());
			    
			    // Establecer parametros y ejecutar SP
			    Map<String,Object> dataDetalle = llamarSPLineas.execute(parametrosDetalle);
			    
			    // Obteniendo el total de filas afectadas al ejecutar SP
			    resultado += (Integer) dataDetalle.get(TOTAL_FILAS_AFECTADAS);
			    
			    // Actualizar Item de mantenimiento
			    resultado += actualizarEstadoItem(item);
		    }
	    }
	    
	    return resultado > 0;
	}
	
	private int actualizarEstadoItem(Item item){
		logger.info("actualizarEstadoItem");
		
		// Instanciando variable para llamado de SP
	    SimpleJdbcCall llamarSP = new SimpleJdbcCall(jdbcTemplate).withProcedureName(SP_ACTUALIZAR_ESTADO_ITEM);

	    // Estableciendo parametros de entrada al SP
	    SqlParameterSource parametros = new MapSqlParameterSource()
	    								.addValue(PARAM_ITEM_CODITEM, item.getCodItem())
	    								.addValue(PARAM_ITEM_ESTADO, item.getEstado());
	    
	    // Establecer parametros y ejecutar SP
	    Map<String,Object> data = llamarSP.execute(parametros);
	    
	    // Obteniendo el total de filas afectadas al ejecutar SP
	    int totalRegistrosAfectado = (Integer) data.get(TOTAL_FILAS_AFECTADAS);
	        
	    return totalRegistrosAfectado;
	}
	
	public int modificarMantenimiento(Mantenimiento mantenimiento){
		logger.info("modificarMantenimiento");
		
		// Instanciando variable para llamado de SP
	    SimpleJdbcCall llamarSP = new SimpleJdbcCall(jdbcTemplate).withProcedureName(SP_MODIFICAR_MANTENIMIENTO);

	    // Estableciendo parametros de entrada al SP
	    SqlParameterSource parametros = new MapSqlParameterSource()
	    								.addValue(PARAM_CODMANTENIMIENTO, mantenimiento.getCodMantenimiento())
	    								.addValue(PARAM_ESTADO, mantenimiento.getEstado());
	    
	    // Establecer parametros y ejecutar SP
	    Map<String,Object> data = llamarSP.execute(parametros);
	    
	    // Obteniendo el total de filas afectadas al ejecutar SP
	    int totalRegistrosAfectado = (Integer) data.get(TOTAL_FILAS_AFECTADAS);
	        
	    return totalRegistrosAfectado;
	}
}
